package azblob

// Code generated by Microsoft (R) AutoRest Code Generator.
// Changes may cause incorrect behavior and will be lost if the code is regenerated.

import (
	"bytes"
	"context"
	"encoding/xml"
	"fmt"
	"github.com/Azure/azure-pipeline-go/pipeline"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"
)

// containerClient is the client for the Container methods of the Azblob service.
type containerClient struct {
	managementClient
}

// newContainerClient creates an instance of the containerClient client.
func newContainerClient(url url.URL, p pipeline.Pipeline) containerClient {
	return containerClient{newManagementClient(url, p)}
}

// Create creates a new container under the specified account. If the container with the same name already exists, the
// operation fails
//
// timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> metadata is optional. Specifies a user-defined name-value pair associated
// with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or
// file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with
// the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version
// 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing
// Containers, Blobs, and Metadata for more information. access is specifies whether data in the container may be
// accessed publicly and the level of access requestID is provides a client-generated, opaque value with a 1 KB
// character limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client containerClient) Create(ctx context.Context, timeout *int32, metadata map[string]string, access PublicAccessType, requestID *string) (*ContainerCreateResponse, error) {
	if err := validate([]validation{
		{targetValue: timeout,
			constraints: []constraint{{target: "timeout", name: null, rule: false,
				chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}},
		{targetValue: metadata,
			constraints: []constraint{{target: "metadata", name: null, rule: false,
				chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil {
		return nil, err
	}
	req, err := client.createPreparer(timeout, metadata, access, requestID)
	if err != nil {
		return nil, err
	}
	resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.createResponder}, req)
	if err != nil {
		return nil, err
	}
	return resp.(*ContainerCreateResponse), err
}

// createPreparer prepares the Create request.
func (client containerClient) createPreparer(timeout *int32, metadata map[string]string, access PublicAccessType, requestID *string) (pipeline.Request, error) {
	req, err := pipeline.NewRequest("PUT", client.url, nil)
	if err != nil {
		return req, pipeline.NewError(err, "failed to create request")
	}
	params := req.URL.Query()
	if timeout != nil {
		params.Set("timeout", fmt.Sprintf("%v", *timeout))
	}
	params.Set("restype", "container")
	req.URL.RawQuery = params.Encode()
	if metadata != nil {
		for k, v := range metadata {
			req.Header.Set("x-ms-meta-"+k, v)
		}
	}
	if access != PublicAccessNone {
		req.Header.Set("x-ms-blob-public-access", fmt.Sprintf("%v", access))
	}
	req.Header.Set("x-ms-version", ServiceVersion)
	if requestID != nil {
		req.Header.Set("x-ms-client-request-id", *requestID)
	}
	return req, nil
}

// createResponder handles the response to the Create request.
func (client containerClient) createResponder(resp pipeline.Response) (pipeline.Response, error) {
	err := validateResponse(resp, http.StatusOK, http.StatusCreated)
	if resp == nil {
		return nil, err
	}
	return &ContainerCreateResponse{rawResponse: resp.Response()}, err
}

// Delete operation marks the specified container for deletion. The container and any blobs contained within it are
// later deleted during garbage collection
//
// timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's
// lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it
// has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a
// blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate only
// on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching
// value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the
// analytics logs when storage analytics logging is enabled.
func (client containerClient) Delete(ctx context.Context, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*ContainerDeleteResponse, error) {
	if err := validate([]validation{
		{targetValue: timeout,
			constraints: []constraint{{target: "timeout", name: null, rule: false,
				chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
		return nil, err
	}
	req, err := client.deletePreparer(timeout, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID)
	if err != nil {
		return nil, err
	}
	resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.deleteResponder}, req)
	if err != nil {
		return nil, err
	}
	return resp.(*ContainerDeleteResponse), err
}

// deletePreparer prepares the Delete request.
func (client containerClient) deletePreparer(timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
	req, err := pipeline.NewRequest("DELETE", client.url, nil)
	if err != nil {
		return req, pipeline.NewError(err, "failed to create request")
	}
	params := req.URL.Query()
	if timeout != nil {
		params.Set("timeout", fmt.Sprintf("%v", *timeout))
	}
	params.Set("restype", "container")
	req.URL.RawQuery = params.Encode()
	if leaseID != nil {
		req.Header.Set("x-ms-lease-id", *leaseID)
	}
	if ifModifiedSince != nil {
		req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
	}
	if ifUnmodifiedSince != nil {
		req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
	}
	if ifMatches != nil {
		req.Header.Set("If-Match", string(*ifMatches))
	}
	if ifNoneMatch != nil {
		req.Header.Set("If-None-Match", string(*ifNoneMatch))
	}
	req.Header.Set("x-ms-version", ServiceVersion)
	if requestID != nil {
		req.Header.Set("x-ms-client-request-id", *requestID)
	}
	return req, nil
}

// deleteResponder handles the response to the Delete request.
func (client containerClient) deleteResponder(resp pipeline.Response) (pipeline.Response, error) {
	err := validateResponse(resp, http.StatusOK, http.StatusAccepted)
	if resp == nil {
		return nil, err
	}
	return &ContainerDeleteResponse{rawResponse: resp.Response()}, err
}

// GetACL sends the get acl request.
//
// timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's
// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character
// limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client containerClient) GetACL(ctx context.Context, timeout *int32, leaseID *string, requestID *string) (*SignedIdentifiers, error) {
	if err := validate([]validation{
		{targetValue: timeout,
			constraints: []constraint{{target: "timeout", name: null, rule: false,
				chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
		return nil, err
	}
	req, err := client.getACLPreparer(timeout, leaseID, requestID)
	if err != nil {
		return nil, err
	}
	resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getACLResponder}, req)
	if err != nil {
		return nil, err
	}
	return resp.(*SignedIdentifiers), err
}

// getACLPreparer prepares the GetACL request.
func (client containerClient) getACLPreparer(timeout *int32, leaseID *string, requestID *string) (pipeline.Request, error) {
	req, err := pipeline.NewRequest("GET", client.url, nil)
	if err != nil {
		return req, pipeline.NewError(err, "failed to create request")
	}
	params := req.URL.Query()
	if timeout != nil {
		params.Set("timeout", fmt.Sprintf("%v", *timeout))
	}
	params.Set("restype", "container")
	params.Set("comp", "acl")
	req.URL.RawQuery = params.Encode()
	if leaseID != nil {
		req.Header.Set("x-ms-lease-id", *leaseID)
	}
	req.Header.Set("x-ms-version", ServiceVersion)
	if requestID != nil {
		req.Header.Set("x-ms-client-request-id", *requestID)
	}
	return req, nil
}

// getACLResponder handles the response to the GetACL request.
func (client containerClient) getACLResponder(resp pipeline.Response) (pipeline.Response, error) {
	err := validateResponse(resp, http.StatusOK)
	if resp == nil {
		return nil, err
	}
	result := &SignedIdentifiers{rawResponse: resp.Response()}
	if err != nil {
		return result, err
	}
	defer resp.Response().Body.Close()
	b, err := ioutil.ReadAll(resp.Response().Body)
	if err != nil {
		return result, NewResponseError(err, resp.Response(), "failed to read response body")
	}
	if len(b) > 0 {
		err = xml.Unmarshal(b, result)
		if err != nil {
			return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body")
		}
	}
	return result, nil
}

// GetMetadata returns all user-defined metadata for the container
//
// timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's
// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character
// limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client containerClient) GetMetadata(ctx context.Context, timeout *int32, leaseID *string, requestID *string) (*ContainerGetMetadataResponse, error) {
	if err := validate([]validation{
		{targetValue: timeout,
			constraints: []constraint{{target: "timeout", name: null, rule: false,
				chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
		return nil, err
	}
	req, err := client.getMetadataPreparer(timeout, leaseID, requestID)
	if err != nil {
		return nil, err
	}
	resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getMetadataResponder}, req)
	if err != nil {
		return nil, err
	}
	return resp.(*ContainerGetMetadataResponse), err
}

// getMetadataPreparer prepares the GetMetadata request.
func (client containerClient) getMetadataPreparer(timeout *int32, leaseID *string, requestID *string) (pipeline.Request, error) {
	req, err := pipeline.NewRequest("GET", client.url, nil)
	if err != nil {
		return req, pipeline.NewError(err, "failed to create request")
	}
	params := req.URL.Query()
	if timeout != nil {
		params.Set("timeout", fmt.Sprintf("%v", *timeout))
	}
	params.Set("restype", "container")
	params.Set("comp", "metadata")
	req.URL.RawQuery = params.Encode()
	if leaseID != nil {
		req.Header.Set("x-ms-lease-id", *leaseID)
	}
	req.Header.Set("x-ms-version", ServiceVersion)
	if requestID != nil {
		req.Header.Set("x-ms-client-request-id", *requestID)
	}
	return req, nil
}

// getMetadataResponder handles the response to the GetMetadata request.
func (client containerClient) getMetadataResponder(resp pipeline.Response) (pipeline.Response, error) {
	err := validateResponse(resp, http.StatusOK)
	if resp == nil {
		return nil, err
	}
	return &ContainerGetMetadataResponse{rawResponse: resp.Response()}, err
}

// GetProperties returns all user-defined metadata and system properties for the specified container. The data returned
// does not include the container's list of blobs
//
// timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's
// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character
// limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client containerClient) GetProperties(ctx context.Context, timeout *int32, leaseID *string, requestID *string) (*ContainerGetPropertiesResponse, error) {
	if err := validate([]validation{
		{targetValue: timeout,
			constraints: []constraint{{target: "timeout", name: null, rule: false,
				chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
		return nil, err
	}
	req, err := client.getPropertiesPreparer(timeout, leaseID, requestID)
	if err != nil {
		return nil, err
	}
	resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getPropertiesResponder}, req)
	if err != nil {
		return nil, err
	}
	return resp.(*ContainerGetPropertiesResponse), err
}

// getPropertiesPreparer prepares the GetProperties request.
func (client containerClient) getPropertiesPreparer(timeout *int32, leaseID *string, requestID *string) (pipeline.Request, error) {
	req, err := pipeline.NewRequest("GET", client.url, nil)
	if err != nil {
		return req, pipeline.NewError(err, "failed to create request")
	}
	params := req.URL.Query()
	if timeout != nil {
		params.Set("timeout", fmt.Sprintf("%v", *timeout))
	}
	params.Set("restype", "container")
	req.URL.RawQuery = params.Encode()
	if leaseID != nil {
		req.Header.Set("x-ms-lease-id", *leaseID)
	}
	req.Header.Set("x-ms-version", ServiceVersion)
	if requestID != nil {
		req.Header.Set("x-ms-client-request-id", *requestID)
	}
	return req, nil
}

// getPropertiesResponder handles the response to the GetProperties request.
func (client containerClient) getPropertiesResponder(resp pipeline.Response) (pipeline.Response, error) {
	err := validateResponse(resp, http.StatusOK)
	if resp == nil {
		return nil, err
	}
	return &ContainerGetPropertiesResponse{rawResponse: resp.Response()}, err
}

// Lease establishes and manages a lock on a container for delete operations. The lock duration can be 15 to 60
// seconds, or can be infinite
//
// action is describes what lease action to take. timeout is the timeout parameter is expressed in seconds. For more
// information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's
// lease is active and matches this ID. breakPeriod is for a break operation, proposed duration the lease should
// continue before it is broken, in seconds, between 0 and 60. This break period is only used if it is shorter than the
// time remaining on the lease. If longer, the time remaining on the lease is used. A new lease will not be available
// before the break period has expired, but the lease may be held for longer than the break period. If this header does
// not appear with a break operation, a fixed-duration lease breaks after the remaining lease period elapses, and an
// infinite lease breaks immediately. duration is specifies the duration of the lease, in seconds, or negative one (-1)
// for a lease that never expires. A non-infinite lease can be between 15 and 60 seconds. A lease duration cannot be
// changed using renew or change. proposedLeaseID is proposed lease ID, in a GUID string format. The Blob service
// returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor (String)
// for a list of valid GUID string formats. ifModifiedSince is specify this header value to operate only on a blob if
// it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only
// on a blob if it has not been modified since the specified date/time. requestID is provides a client-generated,
// opaque value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is
// enabled.
func (client containerClient) Lease(ctx context.Context, action LeaseActionType, timeout *int32, leaseID *string, breakPeriod *int32, duration *int32, proposedLeaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, requestID *string) (*ContainerLeaseResponse, error) {
	if err := validate([]validation{
		{targetValue: timeout,
			constraints: []constraint{{target: "timeout", name: null, rule: false,
				chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
		return nil, err
	}
	req, err := client.leasePreparer(action, timeout, leaseID, breakPeriod, duration, proposedLeaseID, ifModifiedSince, ifUnmodifiedSince, requestID)
	if err != nil {
		return nil, err
	}
	resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.leaseResponder}, req)
	if err != nil {
		return nil, err
	}
	return resp.(*ContainerLeaseResponse), err
}

// leasePreparer prepares the Lease request.
func (client containerClient) leasePreparer(action LeaseActionType, timeout *int32, leaseID *string, breakPeriod *int32, duration *int32, proposedLeaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, requestID *string) (pipeline.Request, error) {
	req, err := pipeline.NewRequest("PUT", client.url, nil)
	if err != nil {
		return req, pipeline.NewError(err, "failed to create request")
	}
	params := req.URL.Query()
	if timeout != nil {
		params.Set("timeout", fmt.Sprintf("%v", *timeout))
	}
	params.Set("comp", "lease")
	params.Set("restype", "container")
	req.URL.RawQuery = params.Encode()
	if leaseID != nil {
		req.Header.Set("x-ms-lease-id", *leaseID)
	}
	req.Header.Set("x-ms-lease-action", fmt.Sprintf("%v", action))
	if breakPeriod != nil {
		req.Header.Set("x-ms-lease-break-period", fmt.Sprintf("%v", *breakPeriod))
	}
	if duration != nil {
		req.Header.Set("x-ms-lease-duration", fmt.Sprintf("%v", *duration))
	}
	if proposedLeaseID != nil {
		req.Header.Set("x-ms-proposed-lease-id", *proposedLeaseID)
	}
	if ifModifiedSince != nil {
		req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
	}
	if ifUnmodifiedSince != nil {
		req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
	}
	req.Header.Set("x-ms-version", ServiceVersion)
	if requestID != nil {
		req.Header.Set("x-ms-client-request-id", *requestID)
	}
	return req, nil
}

// leaseResponder handles the response to the Lease request.
func (client containerClient) leaseResponder(resp pipeline.Response) (pipeline.Response, error) {
	err := validateResponse(resp, http.StatusOK, http.StatusCreated, http.StatusAccepted)
	if resp == nil {
		return nil, err
	}
	return &ContainerLeaseResponse{rawResponse: resp.Response()}, err
}

// ListBlobs the List Blobs operation returns a list of the blobs under the specified container
//
// prefix is filters the results to return only containers whose name begins with the specified prefix. delimiter is
// when the request includes this parameter, the operation returns a BlobPrefix element in the response body that acts
// as a placeholder for all blobs whose names begin with the same substring up to the appearance of the delimiter
// character. The delimiter may be a single character or a string. marker is a string value that identifies the portion
// of the list of containers to be returned with the next listing operation. The operation returns the NextMarker value
// within the response body if the listing operation did not return all containers remaining to be listed with the
// current page. The NextMarker value can be used as the value for the marker parameter in a subsequent call to request
// the next page of list items. The marker value is opaque to the client. maxresults is specifies the maximum number of
// containers to return. If the request does not specify maxresults, or specifies a value greater than 5000, the server
// will return up to 5000 items. Note that if the listing operation crosses a partition boundary, then the service will
// return a continuation token for retrieving the remainder of the results. For this reason, it is possible that the
// service will return fewer results than specified by maxresults, or than the default of 5000. include is include this
// parameter to specify one or more datasets to include in the response. timeout is the timeout parameter is expressed
// in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB
// character limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client containerClient) ListBlobs(ctx context.Context, prefix *string, delimiter *string, marker *string, maxresults *int32, include ListBlobsIncludeType, timeout *int32, requestID *string) (*ListBlobsResponse, error) {
	if err := validate([]validation{
		{targetValue: maxresults,
			constraints: []constraint{{target: "maxresults", name: null, rule: false,
				chain: []constraint{{target: "maxresults", name: inclusiveMinimum, rule: 1, chain: nil}}}}},
		{targetValue: timeout,
			constraints: []constraint{{target: "timeout", name: null, rule: false,
				chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
		return nil, err
	}
	req, err := client.listBlobsPreparer(prefix, delimiter, marker, maxresults, include, timeout, requestID)
	if err != nil {
		return nil, err
	}
	resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.listBlobsResponder}, req)
	if err != nil {
		return nil, err
	}
	return resp.(*ListBlobsResponse), err
}

// listBlobsPreparer prepares the ListBlobs request.
func (client containerClient) listBlobsPreparer(prefix *string, delimiter *string, marker *string, maxresults *int32, include ListBlobsIncludeType, timeout *int32, requestID *string) (pipeline.Request, error) {
	req, err := pipeline.NewRequest("GET", client.url, nil)
	if err != nil {
		return req, pipeline.NewError(err, "failed to create request")
	}
	params := req.URL.Query()
	if prefix != nil {
		params.Set("prefix", *prefix)
	}
	if delimiter != nil {
		params.Set("delimiter", *delimiter)
	}
	if marker != nil {
		params.Set("marker", *marker)
	}
	if maxresults != nil {
		params.Set("maxresults", fmt.Sprintf("%v", *maxresults))
	}
	if include != ListBlobsIncludeNone {
		params.Set("include", fmt.Sprintf("%v", include))
	}
	if timeout != nil {
		params.Set("timeout", fmt.Sprintf("%v", *timeout))
	}
	params.Set("restype", "container")
	params.Set("comp", "list")
	req.URL.RawQuery = params.Encode()
	req.Header.Set("x-ms-version", ServiceVersion)
	if requestID != nil {
		req.Header.Set("x-ms-client-request-id", *requestID)
	}
	return req, nil
}

// listBlobsResponder handles the response to the ListBlobs request.
func (client containerClient) listBlobsResponder(resp pipeline.Response) (pipeline.Response, error) {
	err := validateResponse(resp, http.StatusOK)
	if resp == nil {
		return nil, err
	}
	result := &ListBlobsResponse{rawResponse: resp.Response()}
	if err != nil {
		return result, err
	}
	defer resp.Response().Body.Close()
	b, err := ioutil.ReadAll(resp.Response().Body)
	if err != nil {
		return result, NewResponseError(err, resp.Response(), "failed to read response body")
	}
	if len(b) > 0 {
		err = xml.Unmarshal(b, result)
		if err != nil {
			return result, NewResponseError(err, resp.Response(), "failed to unmarshal response body")
		}
	}
	return result, nil
}

// SetACL sends the set acl request.
//
// containerACL is the acls for the container timeout is the timeout parameter is expressed in seconds. For more
// information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's
// lease is active and matches this ID. access is specifies whether data in the container may be accessed publicly and
// the level of access ifModifiedSince is specify this header value to operate only on a blob if it has been modified
// since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has
// not been modified since the specified date/time. ifMatches is specify an ETag value to operate only on blobs with a
// matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is
// provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when
// storage analytics logging is enabled.
func (client containerClient) SetACL(ctx context.Context, containerACL []SignedIdentifier, timeout *int32, leaseID *string, access PublicAccessType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*ContainerSetACLResponse, error) {
	if err := validate([]validation{
		{targetValue: timeout,
			constraints: []constraint{{target: "timeout", name: null, rule: false,
				chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
		return nil, err
	}
	req, err := client.setACLPreparer(containerACL, timeout, leaseID, access, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID)
	if err != nil {
		return nil, err
	}
	resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.setACLResponder}, req)
	if err != nil {
		return nil, err
	}
	return resp.(*ContainerSetACLResponse), err
}

// setACLPreparer prepares the SetACL request.
func (client containerClient) setACLPreparer(containerACL []SignedIdentifier, timeout *int32, leaseID *string, access PublicAccessType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
	req, err := pipeline.NewRequest("PUT", client.url, nil)
	if err != nil {
		return req, pipeline.NewError(err, "failed to create request")
	}
	params := req.URL.Query()
	if timeout != nil {
		params.Set("timeout", fmt.Sprintf("%v", *timeout))
	}
	params.Set("restype", "container")
	params.Set("comp", "acl")
	req.URL.RawQuery = params.Encode()
	if leaseID != nil {
		req.Header.Set("x-ms-lease-id", *leaseID)
	}
	if access != PublicAccessNone {
		req.Header.Set("x-ms-blob-public-access", fmt.Sprintf("%v", access))
	}
	if ifModifiedSince != nil {
		req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
	}
	if ifUnmodifiedSince != nil {
		req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
	}
	if ifMatches != nil {
		req.Header.Set("If-Match", string(*ifMatches))
	}
	if ifNoneMatch != nil {
		req.Header.Set("If-None-Match", string(*ifNoneMatch))
	}
	req.Header.Set("x-ms-version", ServiceVersion)
	if requestID != nil {
		req.Header.Set("x-ms-client-request-id", *requestID)
	}
	b, err := xml.Marshal(SignedIdentifiers{Value: containerACL})
	if err != nil {
		return req, pipeline.NewError(err, "failed to marshal request body")
	}
	req.Header.Set("Content-Type", "application/xml")
	err = req.SetBody(bytes.NewReader(b))
	if err != nil {
		return req, pipeline.NewError(err, "failed to set request body")
	}
	return req, nil
}

// setACLResponder handles the response to the SetACL request.
func (client containerClient) setACLResponder(resp pipeline.Response) (pipeline.Response, error) {
	err := validateResponse(resp, http.StatusOK)
	if resp == nil {
		return nil, err
	}
	return &ContainerSetACLResponse{rawResponse: resp.Response()}, err
}

// SetMetadata operation sets one or more user-defined name-value pairs for the specified container.
//
// timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's
// lease is active and matches this ID. metadata is optional. Specifies a user-defined name-value pair associated with
// the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to
// the destination blob. If one or more name-value pairs are specified, the destination blob is created with the
// specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version
// 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing
// Containers, Blobs, and Metadata for more information. ifModifiedSince is specify this header value to operate only
// on a blob if it has been modified since the specified date/time. requestID is provides a client-generated, opaque
// value with a 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client containerClient) SetMetadata(ctx context.Context, timeout *int32, leaseID *string, metadata map[string]string, ifModifiedSince *time.Time, requestID *string) (*ContainerSetMetadataResponse, error) {
	if err := validate([]validation{
		{targetValue: timeout,
			constraints: []constraint{{target: "timeout", name: null, rule: false,
				chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}},
		{targetValue: metadata,
			constraints: []constraint{{target: "metadata", name: null, rule: false,
				chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil {
		return nil, err
	}
	req, err := client.setMetadataPreparer(timeout, leaseID, metadata, ifModifiedSince, requestID)
	if err != nil {
		return nil, err
	}
	resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.setMetadataResponder}, req)
	if err != nil {
		return nil, err
	}
	return resp.(*ContainerSetMetadataResponse), err
}

// setMetadataPreparer prepares the SetMetadata request.
func (client containerClient) setMetadataPreparer(timeout *int32, leaseID *string, metadata map[string]string, ifModifiedSince *time.Time, requestID *string) (pipeline.Request, error) {
	req, err := pipeline.NewRequest("PUT", client.url, nil)
	if err != nil {
		return req, pipeline.NewError(err, "failed to create request")
	}
	params := req.URL.Query()
	if timeout != nil {
		params.Set("timeout", fmt.Sprintf("%v", *timeout))
	}
	params.Set("restype", "container")
	params.Set("comp", "metadata")
	req.URL.RawQuery = params.Encode()
	if leaseID != nil {
		req.Header.Set("x-ms-lease-id", *leaseID)
	}
	if metadata != nil {
		for k, v := range metadata {
			req.Header.Set("x-ms-meta-"+k, v)
		}
	}
	if ifModifiedSince != nil {
		req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
	}
	req.Header.Set("x-ms-version", ServiceVersion)
	if requestID != nil {
		req.Header.Set("x-ms-client-request-id", *requestID)
	}
	return req, nil
}

// setMetadataResponder handles the response to the SetMetadata request.
func (client containerClient) setMetadataResponder(resp pipeline.Response) (pipeline.Response, error) {
	err := validateResponse(resp, http.StatusOK)
	if resp == nil {
		return nil, err
	}
	return &ContainerSetMetadataResponse{rawResponse: resp.Response()}, err
}
